<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>12-react商品展示-完整</title>
    <script src="react.development.js" type="text/javascript" charset="UTF-8"></script>
    <script src="react-dom.development.js" type="text/javascript" charset="UTF-8"></script>
    <script src="babel.min.js" type="text/javascript" charset="UTF-8"></script>
</head>
<body>
    <!--你可以将组件当作一种函数或者对象来考虑，根据SRP判定组件的范围。
        一个组件原则上只能负责一个功能，如果它需要负责更多的功能，应该考虑将它拆分成更小的组件
        1、FilterableProductTable：是整个示例应用的整体
        2、SearchBar：接收用户输入的内容
        3、ProductTable：展示产品数据并根据用户输入的内容进行筛选
        4、ProductCategoryRow：为每一种产品类别展示标题
        5、ProductRow：每一行展示一条产品信息
        6、层级关系：FilterableProductTable
                    |--SearchBar
                    |--ProductTable
                       |--ProductCategoryRow
                       |--ProductRow
        7、示例应用拥有的数据：
           |--包含所有产品的原始列表（由props传入，不是state）
           |--用户输入的搜索词（是state）
           |--复选框是否选中的值（是state）
           |--搜索筛选后的产品列表（由原始列表、搜索词、复选框三者计算而来，不是state）
        8、方法体中用到了this，就得必须对方法绑定this
    -->
    <div id="app">

    </div>    
</body>
<script type="text/babel">

    class ProductCategoryRow extends React.Component {
        render() {
            const category = this.props.category;
            return (
                <tr>
                    <th colSpan="2" style={{'text-align':'left'}}>{category}</th>
                </tr>
            );
        }
    }

    class ProductRow extends React.Component {
        render() {
            const product = this.props.product;
            const name = product.stocked ? product.name : <span style={{color: 'red'}}>{product.name}</span>
            return (
                <tr>
                    <td>{name}</td>
                    <td>{product.price}</td>
                </tr>
            );
        }
    }

    class ProductTable extends React.Component {
        render() {
            const rows = [];
            let lastCategory = null;
            const filterText = this.props.filterText;
            const inStockOnly = this.props.inStockOnly;

            this.props.products.forEach((product) => {
                if(product.name.indexOf(filterText) === -1){
                    return;
                }
                if(inStockOnly && !product.stocked) {
                    return;
                }

                if(product.category !== lastCategory) {
                    rows.push(
                        <ProductCategoryRow category={product.category} key={product.category} />
                    );
                }
                rows.push(
                    <ProductRow product={product} key={product.name} />
                );
                lastCategory = product.category;
            });
            return (
                <table>
                    <thead>
                        <tr><th>Name</th><th>Price</th></tr>
                    </thead>
                    <tbody>{rows}</tbody>
                </table>
            );
        }
    }

    class SearchBar extends React.Component {
        constructor(props) {
            super(props);
            this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
            this.handleInStockChange = this.handleInStockChange.bind(this);
        }

        handleFilterTextChange(e) {
            //方法体中用到了this，所以要在ctor中绑定this
            this.props.onFilterTextChange(e.target.value);
        }

        handleInStockChange(e) {
            //方法体中用到了this，所以要在ctor中绑定this
            this.props.onInStockChange(e.target.checked);
        }

        render() {
            const filterText = this.props.filterText;
            const inStockOnly = this.props.inStockOnly;

            return (
                <form>
                    <input type="text" value={filterText} placeholder="search..." 
                           onChange={this.handleFilterTextChange}
                    />
                    <p>
                        <input type="checkbox" checked={inStockOnly} 
                               onChange={this.handleInStockChange}
                        />
                        {' '}Only show products in stock
                    </p>
                </form>
            );
        }
    }

    class FilterableProductTable extends React.Component {
        constructor(props) {
            super(props);
            //SearchBar和ProductTable都用到了filterText、inStockOnly，所以用其公共父组件的state来保存数据
            this.state={filterText:"", inStockOnly:false};
            this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
            this.handleInStockChange = this.handleInStockChange.bind(this);
        }

        //添加反向数据流方法搜索框才能正常使用
        handleFilterTextChange(filterText) {
            //方法体中用到了this，所以要在ctor中绑定this
            this.setState({
                filterText: filterText
            });
        }

        //添加反向数据流方法checkbox才能正常使用
        handleInStockChange(inStockOnly) {
            //方法体中用到了this，所以要在ctor中绑定this
            this.setState({
                inStockOnly: inStockOnly
            });
        }

        render() {
            return (
                <div>
                    <SearchBar filterText={this.state.filterText} inStockOnly={this.state.inStockOnly} 
                               onFilterTextChange={this.handleFilterTextChange}
                               onInStockChange={this.handleInStockChange}
                    />
                    <ProductTable filterText={this.state.filterText} inStockOnly={this.state.inStockOnly} 
                                  products={this.props.products} 
                    />
                </div>
            );
        }
    }

    const PRODUCTS = [
        {category:"Sporting Goods", price:'$49.99', stocked:true, name:'Football'},
        {category:"Sporting Goods", price:'$9.99', stocked:true, name:'Baseball'},
        {category:"Sporting Goods", price:'$19.99', stocked:false, name:'Basketball'},
        {category:"Electronics", price:'$99.99', stocked:true, name:'IPod'},
        {category:"Electronics", price:'$199.99', stocked:false, name:'IPhone5'},
        {category:"Electronics", price:'$399.99', stocked:true, name:'IPhoneX'}
    ];

    ReactDOM.render(
        <FilterableProductTable products={PRODUCTS} />,
        document.getElementById("app")
    );

</script>
</html>